<?php

namespace app\home\controller;

use app\index\home\Home;
use think\Validate;
use think\facade\Log;
use think\Response;
use thans\jwt\facade\JWTAuth;
use app\user\model\CommonUser as CommonUserModel;
use Changguan\SDK\ChangguanSDK;
use Changguan\SDK\Exceptions\SDKException;
use Changguan\SDK\Exceptions\PushException;

/**
 * 常观授权登录控制器
 * @package app\user\home
 */
class Changguan extends Home
{
    /**
     * 常观SDK实例
     * @var ChangguanSDK
     */
    protected $sdk;

    /**
     * 配置项
     * @var array
     */
    protected $config = [];

    /**
     * 初始化方法
     */
    protected function __construct()
    {
        // 初始化配置项
        $this->config = [
            'client_id' => config('changguan.client_id'),
            'client_access_key' => config('changguan.client_access_key'),
            'client_access_secret' => config('changguan.client_access_secret'),
            'push_base_url' => config('changguan.push_base_url'),
            'oauth_base_url' => config('changguan.oauth_base_url'),
            'http_timeout' => config('changguan.http_timeout', 30),
            'http_connect_timeout' => config('changguan.http_connect_timeout', 10),
            'redirect_uri' => config('changguan.redirect_uri'),
            'scopes' => config('changguan.scopes')
        ];

        try {
            $this->sdk = new ChangguanSDK($this->config);
        } catch (SDKException $e) {
            Log::write('常观SDK初始化失败：' . $e->getMessage(), 'error');
            jerror('授权服务初始化失败', 10001);
        }
    }

    /**
     * 网页跳转授权
     * https://hd.netfishing.cn/index.php/user/Changguan/oauth.html?url=https://hd.netfishing.cn/user/changguan/test.html
     */
    public function oauth()
    {
        $url = input('get.url/s', '');
        if (!$url) {
            jerror('跳转链接错误');
        }

        if (empty(session('changguan_user'))) {
            // 保存目标URL
            session('target_url', $url);

            // 生成state参数，防止CSRF攻击
            $state = md5(uniqid(mt_rand(), true));
            session('changguan_state', $state);

            // 构建授权URL
            $params = [
                'client_id' => $this->config['client_id'],
                'redirect_uri' => $this->config['redirect_uri'],
                'response_type' => 'code',
                'scopes' => implode(' ', $this->config['scopes']),
                'state' => $state
            ];

            // 构建完整的授权URL
            $authUrl = $this->config['oauth_base_url'] . '?' . http_build_query($params);

            // 生成外链跳转地址 
            //$authUrl = $this->sdk->redirect()->external($this->config['oauth_base_url'], $params);

            // 重定向到授权页面
            return Response::create('', 'redirect')->header('Location', $authUrl);
        } else {
            // 已有用户信息，直接生成JWT并跳转
            $common_info = CommonUserModel::addChangguanUser(session('changguan_user'));

            $token = JWTAuth::builder(['id' => $common_info['id']]);
            $target_url = add_querystring_var($url, 'common_id', $common_info['id']);
            $target_url = add_querystring_var($target_url, 'token', $token);

            return Response::create('', 'redirect')->header('Location', $target_url);
        }
    }

    public function code()
    {
        // 生成state参数，防止CSRF攻击
        $state = md5(uniqid(mt_rand(), true));
        session('changguan_state', $state);

        $params = [
            'client_id' => $this->config['client_id'],
            'redirect_uri' => $this->config['redirect_uri'],
            'response_type' => 'code',
            'scopes' => implode(' ', $this->config['scopes']),
            'state' => $state
        ];

        jsuccess($params);
    }

    /**
     * 网页授权回调
     */
    public function callback()
    {
        //$target_url = session('target_url');

        // 获取回调参数
        $code = request()->param('code/s');
        $state = request()->param('state/s');

        // 验证state，防止CSRF攻击
        $savedState = session('changguan_state');
        if (empty($savedState) || $savedState !== $state) {
            //jerror('无效的授权请求');
        }

        // 清除session中的state
        session('changguan_state', null);

        // 检查授权码
        if (empty($code)) {
            jerror('未获取到授权码');
        }

        try {
            // 使用授权码获取访问令牌
            $result = $this->sdk->oauth()->getAccessToken($code);

            // 检查是否成功
            if (empty($result) || !isset($result['data']) || empty($result['data']['access_token'])) {
                jerror('获取访问令牌失败');
            }

            $tokenInfo = $result['data'];

            // 获取用户信息
            $userResult = $this->sdk->oauth()->getUserInfo(
                $tokenInfo['access_token'],
                $tokenInfo['open_id']
            );

            if (empty($userResult) || !isset($userResult['data'])) {
                jerror('获取用户信息失败');
            }

            $userInfo = $userResult['data'];

            // 合并令牌信息到用户信息
            $userInfo['access_token'] = $tokenInfo['access_token'];
            $userInfo['refresh_token'] = $tokenInfo['refresh_token'] ?? '';
            $userInfo['expires_in'] = $tokenInfo['expires_in'] ?? 7200;
            $userInfo['openid'] = $tokenInfo['open_id'];

            // 处理系统用户数据
            /*
            $common_info = CommonUserModel::addChangguanUser($userInfo);
            $token = JWTAuth::builder(['id' => $common_info['id']]);
            $target_url = add_querystring_var($target_url, 'common_id', $common_info['id']);
            $target_url = add_querystring_var($target_url, 'token', $token);
            */
            $common_info = CommonUserModel::addChangguanUser($userInfo);
            if (!$common_info) {
                throw new \Exception('授权错误');
            }

            $token = JWTAuth::builder(['id' => $common_info['id']]);

            // 保存用户token 方便注销
            CommonUserModel::where('id', $common_info['id'])->update([
                'user_token' => $token
            ]);

            // session存储用户信息
            session('changguan_user', $userInfo);
            session('changguan_user_token', $token);
        } catch (SDKException $e) {
            Log::write('OAuth授权失败：' . $e->getMessage(), 'error');
            jerror('授权失败');
        } catch (\Exception $e) {
            Log::write('授权流程发生错误：' . $e->getMessage(), 'error');
            jerror('授权过程中发生错误');
        }

        // 重定向到目标URL
        // $this->redirect($target_url);
        jsuccess(['token' => $token]);
    }

    public function notify()
    {
        // 验证签名
        $signatureData = [
            'client_id' => request()->header('cg-client-id'),
            'nonce'     => request()->header('cg-nonce'),
            'timestamp' => request()->header('cg-timestamp'),
            'signature' => request()->header('cg-signature'),
        ] + request()->param();

        // 记录事件日志
        //Log::alert( $signatureData);

        // 验证签名
        if (!$this->sdk->signature()->verifySignature($signatureData)) {
            Log::write('签名验证失败', 'error');
            jerror('签名验证失败');
        }

        // 获取事件类型
        $event = request()->param('event');
        $toUser = request()->param('to_user');

        try {
            // 处理不同类型的事件
            switch ($event) {

                case 'user_info_modified':
                    $field = request()->param('field');
                    $value = request()->param('value');

                    switch ($field) {
                        case 'avatar':
                            CommonUserModel::where('openid', $toUser)
                                ->update(['avatar' => $value]);
                            break;

                        case 'nickname':
                            CommonUserModel::where('openid', $toUser)
                                ->update(['nickname' => $value]);
                            break;

                        case 'mobile':
                            CommonUserModel::where('openid', $toUser)
                                ->update(['mobile' => $value]);
                            break;

                        case 'gender':
                            $genderMap = [
                                '0' => 0,  // 其他
                                '1' => 1,  // 男
                                '2' => 2   // 女
                            ];
                            CommonUserModel::where('openid', $toUser)
                                ->update(['sex' => $genderMap[$value] ?? 0]);
                            break;

                        case 'realname_auth_confirmed':
                            $verifiedMap = [
                                '0' => 0,  // 未认证
                                '1' => 1   // 已认证
                            ];
                            CommonUserModel::where('openid', $toUser)
                                ->update(['face_verified' => $verifiedMap[$value] ?? 0]);
                            break;
                    }
                    break;

                case 'user_status_changed':
                    $status = request()->param('status');
                    $statusMap = [
                        'enabled'  => 1,   // 正常
                        'disabled' => 0,   // 禁用
                        'locked'   => 2    // 锁定
                    ];

                    if (isset($statusMap[$status])) {
                        CommonUserModel::where('openid', $toUser)
                            ->update(['status' => $statusMap[$status]]);

                        // 加入黑名单
                        $userToken = CommonUserModel::where('openid', $toUser)
                            ->value('user_token');
                        JWTAuth::invalidate($userToken);

                        session('changguan_user', null);
                        session('changguan_user_token', null);
                    }
                    break;

                case 'user_logout':
                    // 处理用户登出事件
                    // 加入黑名单
                    $userToken = CommonUserModel::where('openid', $toUser)
                        ->value('user_token');
                    JWTAuth::invalidate($userToken);

                    session('changguan_user', null);
                    session('changguan_user_token', null);
                    break;

                case 'user_revoke':
                    // 处理用户注销事件
                    CommonUserModel::where('openid', $toUser)
                        ->update(['status' => -1]); // -1 表示注销状态

                    // 加入黑名单
                    $userToken = CommonUserModel::where('openid', $toUser)
                        ->value('user_token');
                    JWTAuth::invalidate($userToken);

                    session('changguan_user', null);
                    session('changguan_user_token', null);
                    break;

                case 'user_unauthorized':
                    // 加入黑名单
                    $userToken = CommonUserModel::where('openid', $toUser)
                        ->value('user_token');
                    JWTAuth::invalidate($userToken);

                    session('changguan_user', null);
                    session('changguan_user_token', null);
                    break;
            }
        } catch (\Exception $e) {
            jerror($e->getMessage());
        }

        /*
        Log::alert([
            'type'=> 'notify',
            'event' => $event,
            'toUser' => $toUser
        ]);
        */

        jsuccess($signatureData);
    }

    /**
     * 用户消息推送
     */
    public function push(array $params = [])
    {
        try {
            //
            if (empty($params)) {
                $params = request()->param();
            }

            // 参数验证
            $validate = \think\facade\Validate::rule([
                'template_code'  => 'require|max:50',
                'to_open_id'    => 'require',
                'template_params' => 'array',
                'extend_params'  => 'array',
                'redirect_to'    => 'url'
            ]);
            if (!$validate->check($params)) {
                throw new \Exception($validate->getError());
            }

            // 使用 SDK 的 push 客户端
            $result = $this->sdk->push()
                ->withTemplate($params['template_code'])
                ->withUser($params['to_open_id'])
                ->withParams($params['template_params'] ?: [])
                ->withExtend($params['extend_params'] ?: [])
                ->withRedirect($params['redirect_to'] ? $this->sdk->redirect()->external($params['redirect_to']) : '')
                ->pushToUser();

            // 记录推送日志
            /*
            Log::alert([
                'type'=> 'push',
                'params' => $params,
                'result' => $result
            ]);
            */
            return $result;
        } catch (PushException $e) {
            Log::write('单用户推送失败：' . $e->getMessage() . $params['to_open_id'], 'error');
            throw new \Exception('单用户推送失败：' . $e->getMessage() . $params['to_open_id']);
        }
    }

    /**
     * 广播消息推送
     */
    public function broadcast()
    {
        jerror('未开放');
    }

    /**
     * 创建活动订阅
     */
    public function create_subscription(array $params = [])
    {
        try {
            //
            if (empty($params)) {
                $params = request()->param();
            }

            // 参数验证
            $validate = \think\facade\Validate::rule([
                'name'  => 'require',
                'template_code'    => 'require',
            ]);

            if (!$validate->check($params)) {
                throw new \Exception($validate->getError());
            }

            // 使用 SDK 的 push 客户端
            $result = $this->sdk->push()
                ->withTemplate($params['template_code'])
                ->withSubscriptionName($params['name'])
                ->withSubscriptionDescription($params['description'] ?: '')
                ->createSubscription();

            // 记录推送日志
            /*
            Log::alert([
                'type'=> 'create_subscription',
                'params' => $params,
                'result' => $result
            ]);
            */

            return $result;
        } catch (PushException $e) {
            Log::write('创建活动订阅失败:' . $e->getMessage(), 'error');
            throw new \Exception('创建活动订阅失败' . $e->getMessage());
        }
    }

    /**
     * 用户订阅活动
     */
    public function user_subscription(array $params = [])
    {
        try {
            //
            if (empty($params)) {
                $params = request()->param();
            }

            // 参数验证
            $validate = \think\facade\Validate::rule([
                'subscription_code'  => 'require',
                'to_open_id'    => 'require',
            ]);

            if (!$validate->check($params)) {
                throw new \Exception($validate->getError());
            }

            // 使用 SDK 的 push 客户端
            $result = $this->sdk->push()
                ->withSubscription($params['subscription_code'])
                ->withUser($params['to_open_id'])
                ->subscribeUser();

            // 记录推送日志
            /*
            Log::alert([
                'type'=> 'user_subscription',
                'params' => $params,
                'result' => $result
            ]);
            */

            return $result;
        } catch (PushException $e) {
            Log::write('用户订阅活动失败：' . $e->getMessage(), 'error');
            throw new \Exception('用户订阅活动失败：' . $e->getMessage());
        }
    }

    /**
     * 订阅消息群发
     */
    public function send_subscription(array $params = [])
    {
        try {
            //
            if (empty($params)) {
                $params = request()->param();
            }

            // 参数验证
            $validate = \think\facade\Validate::rule([
                'subscription_code'  => 'require',
                'template_params'    => 'array',
                'extend_params' => 'array',
                'redirect_to' => 'url',
            ]);

            if (!$validate->check($params)) {
                throw new \Exception($validate->getError());
            }

            // 使用 SDK 的 push 客户端
            $result = $this->sdk->push()
                ->withSubscription($params['subscription_code'])
                ->withParams($params['template_params'] ?: [])
                ->withExtend($params['extend_params'] ?: [])
                ->withRedirect($params['redirect_to'] ? $this->sdk->redirect()->external($params['redirect_to']) : '')
                ->triggerSubscription();

            // 记录推送日志
            /*
            Log::alert([
                'type'=> 'send_subscription',
                'params' => $params,
                'result' => $result
            ]);
            */

            return $result;
        } catch (PushException $e) {
            Log::write('订阅消息群发失败：' . $e->getMessage(), 'error');
            throw new \Exception('订阅消息群发失败：' . $e->getMessage());
        }
    }

    /**
     * 刷新访问令牌
     * @param string $refreshToken 刷新令牌
     * @return array|false 成功返回新的令牌信息，失败返回false
     */
    public function refresh($refreshToken)
    {
        try {
            // 刷新访问令牌
            $newToken = $this->sdk->oauth()->refreshToken($refreshToken);

            // TODO更新数据库中的令牌信息
            jsuccess($newToken);
        } catch (SDKException $e) {
            // 记录错误日志
            Log::write('刷新令牌失败：' . $e->getMessage(), 'error');
            jerror('刷新令牌失败：' . $e->getMessage());
        }
    }

    /**
     * 退出登录
     */
    public function logout()
    {
        // 清除会话
        $token = JWTAuth::token();
        if (!$token) {
            jerror('缺少参数');
        }

        JWTAuth::invalidate(JWTAuth::token());
        session('changguan_user', null);

        // 可以根据需要重定向到首页或其他页面
        $url = input('get.url/s', '');
        if ($url) {
            return Response::create('', 'redirect')->header('Location', $url);
        } else {
            jsuccess('退出成功');
        }
    }

    public function test()
    {
        // 清除会话
        $data['user'] = session('changguan_user');
        $data['token'] = request()->param('token/s');
        $data['common_id'] = request()->param('common_id/s');

        jsuccess($data);
    }
}